package com.example.sanguogameserver.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.example.sanguogameserver.consts.RedisKeyConst;
import com.example.sanguogameserver.consts.SanGuoConst;
import com.example.sanguogameserver.dto.Message;
import com.example.sanguogameserver.dto.MessageDTO;
import com.example.sanguogameserver.enums.OnlineEnum;
import com.example.sanguogameserver.response.MessageResp;
import com.example.sanguogameserver.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AsyncMessageService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RedisLockRegistry redisLockRegistry;
    @Autowired
    private PlayerService playerService;

    /**
     * 处理已读消息
     *
     * @param receivePlayerId
     * @param messageResps
     */
    @Async
    public void processMessageRead(Integer receivePlayerId, List<MessageResp> messageResps) {
        // TODO 删除数据库数据
        redisUtil.setObject(RedisKeyConst.Online.name() + receivePlayerId, OnlineEnum.online.name());
        playerService.setOnline(receivePlayerId);
        Map<Integer, List<String>> readMessageMap = messageResps.stream().collect(Collectors.toMap(MessageResp::getFriendPlayerId, (item) -> {
            return item.getMessageDTO().getMessages().stream().map(Message::getMessageId).collect(Collectors.toList());
        }));

        Lock lock = redisLockRegistry.obtain(SanGuoConst.RedisLock.messagePlayerId + receivePlayerId);
        if (lock.tryLock()) {
            try {
                // 把redis消息已读消息删除
                Map<Object, Object> entries = redisUtil.entries(RedisKeyConst.Chat.name() + receivePlayerId);
                for (Map.Entry<Object, Object> entrie : entries.entrySet()) {
                    Integer sendPlayerId = Integer.parseInt(entrie.getKey().toString());
                    // 所有消息id
                    MessageDTO messageDTO = JSON.parseObject(entrie.getValue().toString(), MessageDTO.class);
                    // 已读消息id
                    List<String> messageIds = readMessageMap.get(sendPlayerId);
                    List<Message> remainingMessages = messageDTO.getMessages().stream().filter(item -> !messageIds.contains(item.getMessageId())).collect(Collectors.toList());
                    // 没有剩余消息就删除
                    if (CollUtil.isEmpty(remainingMessages)) {
                        redisUtil.deleteHash(RedisKeyConst.Chat.name() + receivePlayerId, sendPlayerId);
                        continue;
                    }
                    messageDTO.setMessages(remainingMessages);
                    redisUtil.putHash(RedisKeyConst.Chat.name() + receivePlayerId, sendPlayerId, messageDTO, RedisKeyConst.Chat.getDuration());
                }

            } finally {
                //走到这里说明获取锁一定是成功的
                try {
                    lock.unlock();
                } catch (IllegalStateException e) {
                    //业务操作时间过长，会导致锁超时内系统释放，这里就会产生超时异常
                    log.error("释放时发现锁过期", e);
                }

            }
        } else {
            //走到这里说明获取锁一定是失败的的
            log.info("处理已读消息失败,再次处理!");
            processMessageRead(receivePlayerId, messageResps);
        }
    }
}
